package cn.kgc.commons.advice;


import cn.kgc.commons.constant.SystemConstant;
import cn.kgc.commons.exception.ExceptionCodeConfig;
import cn.kgc.commons.exception.HttpException;

import cn.kgc.commons.vo.Result;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;
import java.util.List;

/**
 * <p>处理程序中的异常,将异常信息封装成Result对象</p>
 *
 * @author 王跃
 * @since 2022年09月24日 10:34
 *
 */
//@ControllerAdvice("cn.kgc.controller")
@ConditionalOnClass(ResponseBodyAdvice.class)
public class GlobalExceptionAdvice {
    @Resource
    private ExceptionCodeConfig exceptionCodeConfig;

    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    public Result handleConstraintViolationException(HttpServletRequest request,
                                                     ConstraintViolationException exception){
        String uri= request.getRequestURI();  //请求的地址
        String message=exception.getMessage(); //将验证失败的所有错误信息
        //错误信息的格式:update.email: 邮箱不能为空, update.name: 名字不能为空
        //方法名.参数名:错误信息,方法名.参数名:错误信息 .......
        Result result= Result.builder()     //构建result对象
                    .code(SystemConstant.EXCEPTION_CODE)
                    .requestURL(uri)
                    .data(null)
                     .message(message).build();
        return result;
    }

    /**
     * JSR303 服务器端验证,传入的参数是一个实体类,实体类中的属性验证失败,触发
     * MethodArgumentNotValidException
     * @return  Result
     */
    @ExceptionHandler({MethodArgumentNotValidException.class})
    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    public Result handleMethodArgumentNotValidException
                (HttpServletRequest request,
                 MethodArgumentNotValidException exception){
        String uri=request.getRequestURI(); //请求的地址
        List<ObjectError> objectErrorList=exception
                   .getBindingResult().getAllErrors(); //获得验证失败的ObjectError集合
        String defaultMessage="";//错误信息
        for (ObjectError objectError : objectErrorList) {
            String errorMessage= objectError.getDefaultMessage(); //验证失败的message属性值
            defaultMessage+=errorMessage+";";
        }
        Result result= Result.builder()  //封装Result对象
                        .code(SystemConstant.EXCEPTION_CODE)
                        .data(null).requestURL(uri)
                        .message(defaultMessage).build();
        return result;
    }


    /**
     * 处理自定义异常
     * @param request
     * @param httpException
     * @return
     */
    @ExceptionHandler({HttpException.class})
    public ResponseEntity handleHttpException(HttpServletRequest request,
                                              HttpException httpException){
        String uri=request.getRequestURI(); //获得请求的地址
        int httpExceptionCode=httpException.getCode();  //自定义的异常编码
        //获得异常编码对应的信息
        String message=
                exceptionCodeConfig.getExceptionMessage(httpExceptionCode);
        //获得异常的信息,将异常的信息封装成Result对象
        Result result= Result.builder().requestURL(uri)
                .message(message).code(httpExceptionCode).data(null).build();
        //返回响应体: result对象   格式   状态码
        //int statusCode= httpException.httpStatusCode; //程序中原来的错误编码:500 400 404
        // HttpStatus status=HttpStatus.resolve(statusCode);
        HttpStatus status= HttpStatus.OK;
        HttpHeaders httpHeaders=new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        //封装响应体
        ResponseEntity responseEntity=new ResponseEntity(result,httpHeaders,status);
        return responseEntity;
    }
    /**
     * 处理其他异常
     * @param request
     * @param exception
     * @return
     */
    @ExceptionHandler({Exception.class})
    public ResponseEntity handleException(HttpServletRequest request,
                                          Exception exception) {
        String uri=request.getRequestURI();  //获得请求地址
        String exceptionMessage=
                exceptionCodeConfig.getExceptionMessage(SystemConstant.EXCEPTION_CODE);
        //创建Result对象,包含了异常信息
        Result result= Result.builder().code(SystemConstant.EXCEPTION_CODE).data(null)
                .requestURL(uri).message(exceptionMessage).build();
        //封装响应信息: 响应的状态码   响应的数据的格式  响应的数据
        HttpStatus httpStatus = HttpStatus.OK;
        HttpHeaders httpHeaders=new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        ResponseEntity responseEntity=
                new ResponseEntity(result,httpHeaders,httpStatus);
        return responseEntity;
    }
}
